############## Python-OpenCV Playing Card Detector ###############
#
# Author: Evan Juras
# Date: 9/5/17
# Description: Python script to detect and identify playing cards
# from a PiCamera video feed.
#



import cv2
import os
import time
import numpy as np
import matplotlib.pyplot as plt
import math
import pickle
import hashlib
#import glob
from colormath.color_objects import sRGBColor, LabColor
from colormath.color_conversions import convert_color
import colormath.color_diff

import Cards
import VideoStream

#import DetectCardsLib
from readconfig import ReadConfig
from ApiServer import HttpServer
from threading import Thread
#import BarcodeDetect




#import clr  #clr是公共运行时环境，这个模块是与C#交互的核心
#clr.FindAssembly("PythonNetTest.dll") ## 加载c#dll文件
 
#from PythonNetTest import *    # 导入命名空间
#instance = Class1() #class1是dll里面的类
#print(instance.AddShort(2, 3))#一个简单的加法
#instance.ShowForm() #显示一个窗口

### ---- INITIALIZATION ---- ###
# Define constants and initialize variables
## Camera settings
IM_WIDTH = 1280
IM_HEIGHT = 720 
FRAME_RATE = 10

## Initialize calculated frame rate because it's calculated AFTER the first time it's displayed
frame_rate_calc = 1
freq = cv2.getTickFrequency()

## Define font to use
font = cv2.FONT_HERSHEY_SIMPLEX
data = ReadConfig()
camera_type=int(data.get_config("camera_type"))
camera_src=data.get_config("camera_src")

game_type=data.get_config("game_type")

#server=HttpServer(9991,game_type)

#Thread(target=server.Start,args=()).start()

# Initialize camera object and video feed from the camera. The video stream is set up
# as a seperate thread that constantly grabs frames from the camera feed. 
# See VideoStream.py for VideoStream class definition
## IF USING USB CAMERA INSTEAD OF PICAMERA,
## CHANGE THE THIRD ARGUMENT FROM 1 TO 2 IN THE FOLLOWING LINE:
#videostream = VideoStream.VideoStream((IM_WIDTH,IM_HEIGHT),FRAME_RATE,camera_type,camera_src).start()
#time.sleep(1) # Give the camera time to warm up

# Load the train rank and suit images
path = os.path.dirname(os.path.abspath(__file__))
train_ranks = Cards.load_ranks( path + '/Card_Imgs/')
train_suits = Cards.load_suits( path + '/Card_Imgs/')

# 点是否在外包矩形内
def isPoiWithinBox(poi, sbox, toler=0.0001):
	# sbox=[[x1,y1],[x2,y2]]
	# 不考虑在边界上，需要考虑就加等号
	if poi[0] > sbox[0][0] and poi[0] < sbox[1][0] and poi[1] > sbox[0][1] and poi[1] < sbox[1][1]:
		return True
	if toler > 0:
		pass
	return False

### ---- MAIN LOOP ---- ###
# The main loop repeatedly grabs frames from the video stream
# and processes them to find and identify playing cards.

cam_quit = 0 # Loop control variable
img_path = os.path.dirname(os.path.abspath(__file__)) + '/Card_Imgs/'
# Begin capturing frames
#CARD_SET = 'cartamundi' # grimaud or cartamundi
#DATA_DIR = CARD_SET + '/data/'
#CARDS_DIR = CARD_SET + '/cards/'
##small_size=25
##detect = DetectCardsLib.CardDetection.from_file(DATA_DIR + 'samples_%d.data' % small_size, DATA_DIR + 'responses_%d.data' % small_size)
L1ptStart=None

#Opencv 识别图片
def OpencvDetect(image):
    
    # Pre-process camera image (gray, blur, and threshold it)
    pre_proc = Cards.preprocess_image(image)

    # Find and sort the contours of all cards in the image (query cards)
    cnts_sort, cnt_is_card = Cards.find_cards(pre_proc)

    # If there are no contours, do nothing
    if len(cnts_sort) != 0:

        # Initialize a new "cards" list to assign the card objects.
        # k indexes the newly made array of cards.
        cards = []
        k = 0

        # For each contour detected:
        for i in range(len(cnts_sort)):
            if (cnt_is_card[i] == 1):

                # Create a card object from the contour and append it to the list of cards.
                # preprocess_card function takes the card contour and contour and
                # determines the cards properties (corner points, etc). It generates a
                # flattened 200x300 image of the card, and isolates the card's
                # suit and rank from the image.
                cards.append(Cards.preprocess_card(cnts_sort[i],image))

                # Find the best rank and suit match for the card.
                cards[k].best_rank_match,cards[k].best_suit_match,cards[k].rank_diff,cards[k].suit_diff = Cards.match_card(cards[k],train_ranks,train_suits)

                # Draw center point and match result on the image.
                image = Cards.draw_results(image, cards[k])
                k = k + 1
	    
        # Draw card contours on image (have to do contours all at once or
        # they do not show up properly for some reason)
        if (len(cards) != 0):
            temp_cnts = []
            for i in range(len(cards)):
                if not cards[i].best_rank_match=='Unknown' and not cards[i].best_suit_match=='Unknown':
                    card_name=""
                    card_value=""
                    if game_type=='bac':
                        if isPoiWithinBox(cards[i].center,poly):
                            card_name="p1"
                        elif isPoiWithinBox(cards[i].center,poly1):
                            card_name="p2"
                        elif isPoiWithinBox(cards[i].center,poly2):
                            card_name="p3"
                        elif isPoiWithinBox(cards[i].center,poly3):
                            card_name="p4"
                        elif isPoiWithinBox(cards[i].center,poly4):
                            card_name="p5"
                        elif isPoiWithinBox(cards[i].center,poly5):
                            card_name="p6"
                    elif game_type=='lh':
                        if isPoiWithinBox(cards[i].center,poly):
                            card_name="p1"
                        elif isPoiWithinBox(cards[i].center,poly1):
                            card_name="p2"
                            
                    card_value={"suit":cards[i].best_suit_match.lower(),"rank":cards[i].best_rank_match.lower()}
                    server.PostCardData(card_name,card_value)
                    print('best_rank:{}=suit_match:{}=best_x:{}=best_y:{}'.format(cards[i].best_rank_match,cards[i].best_suit_match,int(cards[i].center[0]),int(cards[i].center[1])))
                    temp_cnts.append(cards[i].contour)
            cv2.drawContours(image,temp_cnts, -1, (255,0,0), 2)


if cam_quit == 0:

    # Grab frame from video stream
    #image = videostream.read()
    image=cv2.imread("Detector.jpg")
    if image is  None:
	    pass
    if len(image)==0:
	    pass

    #print(image.shape)
    if L1ptStart==None and game_type=='bac':
        pic_width=image.shape[1]
        pic_height=image.shape[0]

        L1ptStart = (int(pic_width/4),0)
        L1ptEnd = (int(pic_width/4),int((pic_height/5)*3))
        
        L2ptStart = (int(pic_width/2),0)
        L2ptEnd = (int(pic_width/2),int(pic_height))
        
        L3ptStart = (int((pic_width/4)*3),0)
        L3ptEnd = (int((pic_width/4)*3),int((pic_height/5)*3))
        
        L4ptStart = (0,int((pic_height/5)*3))
        L4ptEnd = (int(pic_width),int((pic_height/5)*3))

        #P1
        poly = [[0, 0], [L1ptEnd[0],L1ptEnd[1]]]
        #P2因为L2是贯穿的
        poly1 = [[L1ptStart[0], L1ptStart[1]], [L2ptEnd[0],L2ptEnd[1]/5*3]]
        #P3
        poly2 = [[L2ptStart[0], L2ptStart[1]], [L3ptEnd[0],L3ptEnd[1]]]
        #P4
        poly3 = [[L3ptStart[0], L3ptStart[1]], [L4ptEnd[0],L4ptEnd[1]]]
        #P5
        poly4 = [[L4ptStart[0], L4ptStart[1]], [L2ptEnd[0],L2ptEnd[1]]]
        #P6
        poly5 = [[L2ptEnd[0],L2ptEnd[1]/5*3], [pic_width,pic_height]]
    elif L1ptStart==None and game_type=='lh':
        pic_width=image.shape[1]
        pic_height=image.shape[0]

        L1ptStart = (int(pic_width/2),0)
        L1ptEnd = (int(pic_width/2),pic_height)


        #P1
        poly = [[0, 0], [L1ptEnd[0],L1ptEnd[1]]]
        #P2因为L2是贯穿的
        poly1 = [[L1ptStart[0], L1ptStart[1]], [pic_width,pic_height]]
    
    ##img, color_img = DetectCardsLib.load_and_convert_img(image)
	
    ##cards, debug_img = detect.detect_cards_in_image(img, color_img, True)
    ##if len(cards) != 0:
        ##print(cards)
        ##for i in range(len(cards)):
            ##cv2.putText(image,"Result: "+str(cards[i][0]),(int(cards[i][1][0]),int(cards[i][1][1])),font,0.7,(255,0,255),2,cv2.LINE_AA)
    # Start timer (for calculating frame rate)
    t1 = cv2.getTickCount()

    
    OpencvDetect(image)
    #BarcodeDetect.DBarCode(image)
    # Draw framerate in the corner of the image. Framerate is calculated at the end of the main loop,
    # so the first time this runs, framerate will be shown as 0.
    cv2.putText(image,"FPS: "+str(int(frame_rate_calc)),(10,26),font,0.7,(255,0,255),2,cv2.LINE_AA)


    
    if game_type=='bac' or game_type=='lh':
        #画辅助线
        # L1起点和终点的坐标
        point_color = (0, 255, 0) # BGR
        thickness = 1 
        lineType = 4
        cv2.line(image, L1ptStart, L1ptEnd, point_color, thickness, lineType)
    elif  game_type=='bac':
        #L2起点和终点的坐标
        point_color = (0, 0, 225) # BGR
        thickness = 1 
        lineType = 8
        cv2.line(image, L2ptStart, L2ptEnd, point_color, thickness, lineType)
        #L3起点和终点的坐标
        point_color = (0, 255, 0) # BGR
        thickness = 1 
        lineType = 8
        cv2.line(image, L3ptStart, L3ptEnd, point_color, thickness, lineType)
        #L4起点和终点的坐标
        point_color = (0, 255, 225) # BGR
        thickness = 2 
        lineType = 8
        cv2.line(image, L4ptStart, L4ptEnd, point_color, thickness, lineType)


    # Finally, display the image with the identified cards!
    cv2.imshow("Card Detector",image)

    # Calculate framerate
    t2 = cv2.getTickCount()
    time1 = (t2-t1)/freq
    frame_rate_calc = 1/time1
    

    print('Press "c" to continue.')
    key = cv2.waitKey(0) & 0xFF
    if key == ord('c'):
        pass
    # Poll the keyboard. If 'q' is pressed, exit the main loop.
    key = cv2.waitKey(1) & 0xFF
    if key == ord("q"):
        cam_quit = 1
        

# Close all windows and close the PiCamera video stream.
cv2.destroyAllWindows()
#videostream.stop()
#server.Stop()

